package com.hanter.downloader.demo

import android.Manifest
import android.content.ContentValues
import android.content.Context
import android.database.Cursor
import android.database.sqlite.SQLiteConstraintException
import android.net.Uri
import android.os.Build
import android.os.Bundle
import android.os.Environment
import android.provider.BaseColumns
import android.provider.MediaStore
import android.util.Log
import android.view.View
import android.webkit.MimeTypeMap
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.FileProvider
import com.hanter.downloader.Downloader
import com.hanter.downloader.RequestListener
import com.hanter.downloader.demo.databinding.ActivityMainBinding
import com.hanter.downloader.exception.ResponseException
import java.io.File

class MainActivity : AppCompatActivity(), View.OnClickListener {

    companion object {
        const val TAG = "MainActivity"
    }

    private val binding by lazy {
        ActivityMainBinding.inflate(layoutInflater)
    }

    private var request: Downloader.Request? = null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(binding.root)
        Downloader.get(this).config = Downloader.Config(20000, 20000, 4096)
//        Downloader.get(this).setDownloadService(OkhttpService(this))
    }

    override fun onClick(v: View?) {
        when (v?.id) {
            R.id.btnPermission -> {
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                    requestPermissions(arrayOf(Manifest.permission.READ_EXTERNAL_STORAGE), 1)
                }
            }

            R.id.btnDownload -> {
                Log.e(TAG, "click download")
                testTask()
            }

            R.id.btnCancel -> {
                Log.e(TAG, "click cancel")
                request?.cancel()
            }

            R.id.btnPause -> {
                Log.e(TAG, "click pause")
                request?.pause()
            }

            R.id.btnResume -> {
                Log.e(TAG, "click resume")
                request?.resume()
            }
        }
    }

    private fun testTask() {
//        MediaStore.Downloads.getContentUri("external")
//
//        MediaStore.Images.Media.EXTERNAL_CONTENT_URI
//
//        val contentValues = ContentValues()
//        contentResolver.insert()
//        val file = File(getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS), "/test/test.zip")

        val file = File(
            Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS),
            "/test/test.zip"
        )
//        val executor = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors() * 2 + 1)
//        val task = DownloadTask(this, executor, "https://xz71.sccnn.com/0001/73583-20211020160026.rar", "test.rar", file.absolutePath)
//        val task = DownloadTask(this, executor, "https://cdn.stocksnap.io/img-thumbs/960w/hot-air_XKK9GEAVAR.jpg", "test.rar", file.absolutePath)


        request = Downloader.get(this)
//            .load("https://stackoverflow.com/")
            .load("https://gw.alipayobjects.com/os/bmw-prod/7555c027-6dc5-4307-916c-83baf23fa7c3.zip")
//            .load("https://cdn.stocksnap.io/img-thumbs/960w/hot-air_XKK9GEAVAR.jpg")
            .uri(createExternalUri("test.zip"))
//            .file(file)
            .listener(object : RequestListener {
                override fun onStart() {

                }

                override fun onProgress(progress: Long, max: Long) {
//                    Log.d(TAG, "length: $max, progress: $progress")
                    binding.pgbProgress.progress = (progress * 100f / max).toInt()
                }

                override fun onResponse(path: String?) {
                    Log.e(TAG, "onResponse")

                    Toast.makeText(
                        this@MainActivity,
                        "下载完成-${System.currentTimeMillis()}",
                        Toast.LENGTH_SHORT
                    ).show()
                }

                override fun onError(e: ResponseException) {
                    e.cause?.printStackTrace()
                    Log.e(TAG, "onError")
                    Toast.makeText(
                        this@MainActivity,
                        "下载失败-${System.currentTimeMillis()}",
                        Toast.LENGTH_SHORT
                    ).show()
                }

                override fun onCancel() {
                    Log.e(TAG, "onCancel")

                    Toast.makeText(
                        this@MainActivity,
                        "下载取消-${System.currentTimeMillis()}",
                        Toast.LENGTH_SHORT
                    ).show()
                }

                override fun onFinish() {
                    Log.e(TAG, "onFinish")
                }
            })
            .download()

        /*
        window?.decorView?.postDelayed({
            Log.d(TAG, "取消。。。")
            request?.cancel()
        }, 800)
        */

        /*
        val service = ForkJoinPool(2)

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            ForkJoinPool.commonPool().submit(
                DownloadForkTask(0, 512)
            )
        }
        */

        /*
        Downloader.get(this)
            .load("https://gw.alipayobjects.com/os/bmw-prod/7555c027-6dc5-4307-916c-83baf23fa7c3.zip")
            .rename("test.zip")
            .path(file.absolutePath)
            .listener(object : RequestListener {
                override fun onFinish() {
                    Log.d("Test", "下载结束")
                }

                override fun onProgress(progress: Long, max: Long) {
                    Log.d("Test", "$progress/$max")
                }

                override fun onResponse(path: String?) {
                    Log.d("Test", "下载成功$path")
                }

                override fun onCancel() {
                    Log.d("Test", "下载取消")
                }

                override fun onError(err: Int, msg: String?) {
                    Log.d("Test", "下载失败$err")
                }

                override fun onStart() {

                }
            })
            .download()
        */

//        val task = DownloadTask(this, executor, "https://gw.alipayobjects.com/os/bmw-prod/7555c027-6dc5-4307-916c-83baf23fa7c3.zip", "test.zip", file.absolutePath)
//        val task = DownloadTask(this, executor, "https://www.baidu.com/img/PCtm_d9c8750bed0b3c7d089fa7d55720d6cf.png", "test.png", file.absolutePath)
//        executor.execute(task)
    }

    private fun createFileUri(fileName: String): Uri? {
        val mediaFile = File(this.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS), "test.zip")
        val parentFile = mediaFile.parentFile
        if (parentFile != null && !parentFile.exists()) {
            parentFile.mkdirs()
        }
        if (!mediaFile.exists()) {
            mediaFile.createNewFile()
        }
        return FileProvider.getUriForFile(this, "$packageName.fileprovider", mediaFile)
    }

    private fun createFile(fileName: String, public: Boolean): File {
        val dir = if (public) {
            Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS)
        } else {
            this.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS)
        }

        val mediaFile = File(dir, fileName)
        if (!mediaFile.exists()) {
            val parentFile = mediaFile.parentFile
            if (parentFile != null && !parentFile.exists()) {
                parentFile.mkdirs()
            }
            mediaFile.createNewFile()
        }

        return mediaFile
    }

    private fun createExternalUri(fileName: String): Uri? {
        val contentValues = ContentValues()
        contentValues.put(MediaStore.Images.Media.DISPLAY_NAME, fileName)
        val filePath = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
            // 参考：https://developer.android.com/reference/android/provider/MediaStore.MediaColumns#RELATIVE_PATH
            // android Q中不再使用DATA字段，而用RELATIVE_PATH代替，RELATIVE_PATH是相对路径不是绝对路径
            // 如果文件 /storage/0000-0000/DCIM/Vacation/IMG1024.JPG 则它的路径为 DCIM/Vacation/
            // 可以传空，但会根据媒体类型自动选择目录；如果你填了 audio/mpeg 到 PICTURES 会报错，类型相关目录
            // 根据 type 选择 路径
            contentValues.put(MediaStore.MediaColumns.RELATIVE_PATH, "Download" + File.separator)
            contentValues.put(MediaStore.MediaColumns.IS_PENDING, 0)
            "Download" + File.separator

//            contentValues.put(MediaStore.MediaColumns.RELATIVE_PATH, "Pictures" + File.separator + "test" + File.separator)
//            contentValues.put(MediaStore.Images.Media.IS_PENDING, 0)
//            "Pictures" + File.separator + "test" + File.separator
        } else {
            // 低于 Q 手动创建，然后授权 读写
            val mediaFile: File = createFile(fileName, true)
//            MimeTypeMap.getSingleton().getMimeTypeFromExtension()

            val dataPath = mediaFile.absolutePath

//            val dataPath = mediaFile.path.substring(
//                Environment.getExternalStorageDirectory().absolutePath.length,
//                mediaFile.path.length
//            )
            contentValues.put(MediaStore.MediaColumns.DATA, dataPath)
            dataPath
        }

        contentValues.put(
            MediaStore.MediaColumns.MIME_TYPE,
            MimeTypeMap.getSingleton().getMimeTypeFromExtension("zip")
        )


        val uri = MediaStore.Files.getContentUri("external")

//        val uri = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
//            MediaStore.Downloads.EXTERNAL_CONTENT_URI
//        } else {
//            MediaStore.Files.getContentUri("external")
//        }


//        val exists = AndroidUriUtils.checkUriExists(this, uri, fileName, filePath)
//        val rename = checkOrRename(this, uri, fileName, filePath)
//        contentValues.put(MediaStore.Images.Media.DISPLAY_NAME, rename)
//        Log.d("Test", "exists: $exists")
//        Log.d("Test", "name: $rename")


//        val delete = checkOrDelete(this, uri, fileName, filePath)
//        Log.d("Test", "delete: $delete")
//        contentValues.put(MediaStore.Images.Media.DISPLAY_NAME, fileName)

        /*
        val mediaUri = AndroidUriUtils.getUriIfExists(this, uri, fileName, filePath)
        if (mediaUri != null || AndroidUriUtils.checkUriExists(this, uri, fileName, filePath)) {

            if (mediaUri != null)
                return mediaUri

            if (mediaUri != null && AndroidUriUtils.exists(this, mediaUri)) {
                Log.d("Test", "文件存在")
                return mediaUri
            }

            throw IOException("已存在文件名")
        }

        if (mediaUri != null && AndroidUriUtils.exists(this, mediaUri)) {
            throw IOException("文件不存在，删除")
        }
        */

        var i = 0
        while (true) {
            try {
                val displayName = contentValues.getAsString(MediaStore.Images.Media.DISPLAY_NAME)
                val mediaUri = AndroidUriUtils.getUriIfExists(this, uri, displayName, filePath)
                if (mediaUri != null) {
                    return mediaUri
                }

                return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
                    contentResolver.insert(
                        uri,
                        contentValues
                    )
                } else {
                    getUriFromFile(this, filePath)
                }

            } catch (e: SQLiteConstraintException) {
                // 已存在同名文件
                i++
                Log.d("Test", "重命名：$i")
                val name = renameUri(this, fileName, i)
                contentValues.put(MediaStore.Images.Media.DISPLAY_NAME, name)
            } catch (e: Exception) {
                e.printStackTrace()
            }
        }
    }

    private val EXTERNAL_CONTENT_URI = MediaStore.Files.getContentUri("external")

    fun getUriFromFile(context: Context, path: String): Uri? {
        val cursor: Cursor = context.contentResolver.query(
            MediaStore.Files.getContentUri("external"),
            arrayOf(BaseColumns._ID),
            MediaStore.MediaColumns.DATA + " = ?",
            arrayOf(path),
            MediaStore.MediaColumns.DATE_ADDED + " desc"
        ) ?: return null


        return cursor.use {
            // 是否存在
            if (cursor.moveToFirst()) {
                val fileId = cursor.getLong(cursor.getColumnIndex(BaseColumns._ID))
                MediaStore.Files.getContentUri("external", fileId)
            } else {
                val values = ContentValues()
                values.put(MediaStore.MediaColumns.DATA, path)
                context.contentResolver.insert(
                    MediaStore.Files.getContentUri("external"),
                    values
                )
            }
        }
    }

    // RecoverableSecurityException: com.hanter.downloader.demo has no access to content://media/external/images/media/137455
    private fun checkOrDelete(
        context: Context,
        contentUri: Uri,
        fileName: String,
        filePath: String
    ): Boolean {
        if (AndroidUriUtils.checkUriExists(context, contentUri, fileName, filePath)) {
            AndroidUriUtils.getUriIfExists(this, contentUri, fileName, filePath)?.let { uri ->
                return contentResolver.delete(uri, null, null) > 0
            }
        }
        return false
    }

    private fun renameUri(context: Context, fileName: String, i: Int): String {
        var name = fileName
        val dotPos = fileName.lastIndexOf(".")
        var suffix: String? = null
        val n = if (dotPos == -1) {
            fileName
        } else {
            suffix = fileName.substring(dotPos + 1, fileName.length)
            fileName.substring(0, dotPos)
        }
        return "$n ($i).$suffix"
    }

    private fun checkOrRename(
        context: Context,
        uri: Uri,
        fileName: String,
        filePath: String
    ): String {
        var name = fileName
        val dotPos = fileName.lastIndexOf(".")
        var suffix: String? = null
        val n = if (dotPos == -1) {
            fileName
        } else {
            suffix = fileName.substring(dotPos + 1, fileName.length)
            fileName.substring(0, dotPos)
        }
        var i = 0
        while (AndroidUriUtils.checkUriExists(context, uri, name, filePath)) {
            i++
            name = if (suffix != null) {
                "$n ($i).$suffix"
            } else {
                n
            }
        }
        return name
    }

    /*
    private fun insert(contentUri: Uri, contentValues: ContentValues): Uri {
        try {
            contentResolver.insert(
                contentUri,
                contentValues
            )
        } catch (e: SQLiteConstraintException) {
            // 重名问题
            val fileName = contentValues.getAsString(MediaStore.Images.Media.DISPLAY_NAME)

        }
    }
    */

}
